package com.triplelink.builder.query;

import java.lang.reflect.Field;
import java.util.Stack;

import com.triplelink.annotations.DatatypeProperty;
import com.triplelink.context.Connector;
import com.triplelink.exception.TripleLinkException;
import com.triplelink.to.steak.InstancePartTO;
import com.triplelink.util.ClassTypeUtil;
import com.triplelink.util.EntityUtil;

public class MergeQueryBuilder
{
	public static QueryTL build(Object entity, String abox, Connector connector)
	{
		try
		{
			return build(EntityUtil.getIdOrCreate(entity), entity, abox, connector);
		}
		catch (IllegalArgumentException e)
		{
			throw new TripleLinkException(e);
		}
		catch (IllegalAccessException e)
		{
			throw new TripleLinkException(e);
		}
	}
	
	public static QueryTL build(String id, Object entity, String abox, Connector connector)
	{
		QueryTL deletePart = QueryTL.create(connector);
		QueryTL insertPart = deletePart.shareResources();
		QueryTL wherePart = deletePart.shareResources();
		
		try
		{
			deletePart
			.append("WITH <").append(abox).append("> \n")
			.append("DELETE \n")
			.append("{ \n")
			.plusTab();
			
			insertPart
			.append("INSERT \n")
			.append("{ \n")
			.plusTab();
			
			wherePart
			.append("WHERE \n")
			.append("{ \n")
			.plusTab();
			
			build(id, entity, deletePart, insertPart, wherePart);
			
			deletePart
			.append("} \n");
			
			insertPart
			.append("} \n");
			
			wherePart
			.append("} \n");
			
			deletePart.getSb()
			.append(insertPart.getSb())
			.append(wherePart.getSb());
			
			return deletePart;
		}
		catch (IllegalArgumentException e)
		{
			throw new TripleLinkException(e);
		}
		catch (IllegalAccessException e)
		{
			throw new TripleLinkException(e);
		}
	}
	
	public static void build(String id, Object entity, QueryTL deletePart, QueryTL insertPart, QueryTL wherePart) throws IllegalArgumentException, IllegalAccessException
	{
		Stack<InstancePartTO> stack = new Stack<InstancePartTO>();
		
		DeleteQueryBuilder.putFilterId(id, deletePart, wherePart);
		
		ClassTypeUtil.putClassType(entity, id, insertPart);
		
		push(id, entity, true, stack, deletePart, insertPart, wherePart);
		
		while (!stack.isEmpty())
		{
			InstancePartTO item = stack.pop();
			
			for (Field field : item.getClassEntity().getDeclaredFields())
				putValue(field, item, stack, deletePart, insertPart, wherePart);
		}
	}
	
	private static void push(String id, Object entity, boolean cascadeSave, Stack<InstancePartTO> stack, QueryTL deletePart, QueryTL insertPart, QueryTL wherePart) throws IllegalArgumentException, IllegalAccessException
	{
		Class<?> currentClass = entity.getClass();
		
		while (currentClass != null)
		{
			stack.push(new InstancePartTO(id, entity, currentClass, cascadeSave));
			
			currentClass = currentClass.getSuperclass();
		}
	}
	
	private static void putValue(Field field, InstancePartTO item, Stack<InstancePartTO> stack, QueryTL deletePart, QueryTL insertPart, QueryTL wherePart) throws IllegalArgumentException, IllegalAccessException
	{
		field.setAccessible(true);
		
		DatatypeProperty datatypeProperty = field.getAnnotation(DatatypeProperty.class);
		
		if (datatypeProperty != null)
		{
			InsertQueryBuilder.putValue(field, item.getEntity(), item.getId(), datatypeProperty, insertPart);
		}
		
	}
}